package epoch.game.core.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.logging.log4j.message.ParameterizedMessage;

import epoch.game.core.common.Loggers;
import epoch.game.core.exception.SysException;
import epoch.game.core.server.ISession;

/**
 * 工具类
 * @author will
 * @date 2016年4月1日 下午4:06:00
 */
public final class Utils {

	/**
	 * 判定类型是否为基础类型
	 * 检查范围【byte,short,int long,float,double,boolean,String】
	 * @param clasz
	 * @return
	 */
	public static boolean isSimpleType(Class<?> clasz){
		if(int.class==clasz || Integer.class==clasz || byte.class==clasz || Byte.class==clasz || short.class==clasz||Short.class==clasz
				||long.class==clasz||Long.class==clasz||float.class==clasz|| Float.class==clasz||double.class==clasz||Double.class==clasz
				|| boolean.class==clasz||Boolean.class==clasz || String.class==clasz){
			return true;
		}
		return false;
	}

	/**
	 * 字符合法性检查 过滤掉utf8不支持的字符{数字0-9,大小写a-z,中文,检查范围}
	 * @param str
	 * @param maxLen 字符最大长度
	 * @return
	 */
	public static boolean isUtf8Support(String str, int maxLen) {
		if (str==null || str.length()==0)
			return true;
		boolean result = str.matches("[0-9a-zA-Z\u3400-\u4DB5\u4E00-\u9FA5\u9FA6-\u9FBB\uF900-\uFA2D\uFA30-\uFA6A\uFA70-\uFAD9\uFF00-\uFFEF\u2E80-\u2EFF\u3000-\u303F\u31C0-\u31EF]{1," + maxLen + "}");
		return result;
	}
	
	/**
	 * 检测字符串是否仅由换行符,以及32~126的Ascii码与中文字符组成
	 * @param str
	 * @param maxLen
	 * @return
	 */
	public static boolean isAsciiOrChinese(String str, int maxLen) {
		if (str==null || str.length()==0)
			return true;
		boolean result = str.matches("[\\u000A\u0020-\u007E-\u00FF\u3400-\u4DB5\u4E00-\u9FA5\u9FA6-\u9FBB\uF900-\uFA2D\uFA30-\uFA6A\uFA70-\uFAD9\uFF00-\uFFEF\u2E80-\u2EFF\u3000-\u303F\u31C0-\u31EF]{1," + maxLen + "}");
		return result;
	}
	
	/**
	 * 根据数组构建字符串
	 * @param objArr
	 * @return
	 */
	public static String buildStr(Object[] objArr){
		StringBuilder sb = new StringBuilder();
		sb.append("param=");
		if(objArr==null){
			sb.append("null");
		}else{
			sb.append("[");
			if(objArr.length>0){
				for(Object obj : objArr){
					sb.append(obj).append(",");
				}
				sb.delete(sb.length()-1, sb.length());
			}
			sb.append("]");
		}
		return sb.toString();
	}
	
	/**
	 * 构建整形数组
	 * @param arrayStr
	 * @param seperator
	 * @return
	 */
	public static int[] buildIntArray(String arrayStr, String seperator){
		if(arrayStr==null || arrayStr.isEmpty()){
			return new int[0];
		}
		String[] strs = arrayStr.split(seperator);
		int[] result = new int[strs.length];
		for(int i=0; i<strs.length; i++){
			result[i] = Integer.parseInt(strs[i]);
		}
		return result;
	}
	
	/**
	 * 基于参数创建字符串
	 * #0开始
	 * @param str
	 * @param params
	 * @return
	 */
	public static String createStr(String str, Object...params) {
		return ParameterizedMessage.format(str, params);
	}
		
	/**
	 * 获取堆外内存信息
	 * @return Map<reserved: 已申请堆外内存, max:最大可申请堆外内存>
	 */
	public static Map<String, Long> memoryDirectInfo() {
		try {
			Class<?> c = Class.forName("java.nio.Bits");
			
			//已申请堆外内存
			Field reserved = c.getDeclaredField("reservedMemory");
			reserved.setAccessible(true);
			Object reservedObj = reserved.get(null);
			Long reservedValue = -1L;
			if(reservedObj instanceof Long || reservedObj.getClass()==long.class){
				reservedValue = (Long)reservedObj;
			}else if(reservedObj instanceof AtomicLong){
				reservedValue = ((AtomicLong)reservedObj).get();
			}
			
			//最大可申请堆外内存
			Field max = c.getDeclaredField("maxMemory");
			max.setAccessible(true);
			Object maxObj = max.get(null);
			Long maxValue = -1L;
			if(maxObj instanceof Long || maxObj.getClass()==long.class){
				maxValue = (Long)maxObj;
			}else if(maxObj instanceof AtomicLong){
				maxValue = ((AtomicLong)maxObj).get();
			}
			return Utils.ofMap("reserved", reservedValue, "max", maxValue);
		} catch(Exception e) {
			throw new SysException(e);
		}
	}
	
	/**
	 * 构造Map对象
	 * @param <T>
	 * @param ts
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <K, V> Map<K, V> ofMap(Object...params) {
		LinkedHashMap<K, V> result = new LinkedHashMap<K, V>();
		//无参 返回空即可
		if(params == null || params.length == 0) {
			return result;
		}
		//处理成对参数
		int len = params.length;
		for (int i = 0; i < len; i += 2) {
			K key = (K) params[i];
			V val = (V) params[i + 1];
			
			result.put(key, val);
		}
		return result;
	}
	
	public static final long SIZE_KB = 1024;
	public static final long SIZE_MB = 1024 * 1024;

	/**
	 * 格式化字节流大小显示<BR/>
	 * 大于5MB 单位显示MB<BR/>
	 * 大于5KB 单位显示KB<BR/>
	 * 其余直接显示字节B
	 * 
	 * @return
	 */
	public static String formatByteSize(long byteSize) {
		return byteSize > 5 * SIZE_MB ? (byteSize / SIZE_MB + "MB") : (byteSize > 5 * SIZE_KB ? (byteSize / SIZE_KB + "KB") : (byteSize + "B"));
	}

	public static int bytesToInt(byte[] b,int offset) {
		int num = 0;
		for(int i = offset; i < offset+4; ++i) {
			num <<= 8;
			num |= (b[i] & 0xff);
		}
		return num;
	}
	
	/**
	 * 关闭连接
	 * @param session
	 * @param reason
	 */
	public static void closeSession(ISession session, String reason){
		closeSession(session, true, reason);
	}
	
	/**
	 * 关闭连接
	 * @param session
	 * @param force 是否忽略未执行完的任务
	 * @param reason
	 */
	public static void closeSession(ISession session, boolean force, String reason){
		Loggers.SESSION_CLOSE_LOG.info("sessionId="+session.getId()+","+session+" closed->"+reason);
		session.close(force);
	}
	
	/**
	 * 关闭连接
	 * @param session
	 * @param force
	 * @param reason
	 * @param delay 延迟关闭毫秒数
	 */
	public static void closeSession(ISession session, boolean force, String reason, long delay){
		Loggers.SESSION_CLOSE_LOG.info("sessionId="+session.getId()+","+session+" closed->"+reason);
		session.close(force, delay);
	}
	
	/**
	 * 保存文件和内容
	 * 
	 * @param path
	 * @param content
	 */
	public static void save(String path, String content) {
		save(path,content,"UTF-8");
	}
	
	/**
	 * 保存文件和内容
	 * 
	 * @param path
	 * @param content
	 */
	public static void save(String path, String content, String charsetName) {
		File file = new File(path);
		try {
			file.createNewFile();
			FileOutputStream fos = new FileOutputStream(file);
			OutputStreamWriter osw = new OutputStreamWriter(fos, charsetName);
			osw.write(content);
			osw.flush();
			osw.close();
			fos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 参数检测
	 * @param condition
	 * @param message
	 */
	public static void argRequire(boolean condition, String message) {
		if (!condition) {
			throw new IllegalArgumentException(message);
		}
	}

	/**
	 * 参数检测
	 * 
	 * @param number
	 * @param min
	 * @param max
	 * @param message
	 */
	public static void argRequireInRange(int number, int min, int max, String message) {
		if (number < min || number > max) {
			throw new IllegalArgumentException(message);
		}
	}
	
}
